package controllers

import (
	"autoPage/models"
	"encoding/json"
	"errors"
	"github.com/astaxie/beego"
	"github.com/pquerna/ffjson/ffjson"
	"mime/multipart"
	"net/url"
	"strconv"
	"strings"
	"time"
)

// InterfaceusageController operations for Interfaceusage
type InterfaceusageController struct {
	BaseController
}

// URLMapping ...
func (c *InterfaceusageController) URLMapping() {
	c.Mapping("Post", c.Post)
	c.Mapping("GetOne", c.GetOne)
	c.Mapping("Delete", c.Delete)
	c.Mapping("List", c.List)
	c.Mapping("Update", c.Update)
	c.Mapping("Edit", c.Edit)
	c.Mapping("Add", c.Add)
	c.Mapping("GetParams", c.GetParams)
	c.Mapping("TryInterface", c.TryInterface)
	c.Mapping("GenerateData", c.GenerateData)
}

func (c *InterfaceusageController) GetURLQuery() url.Values {
	return c.Ctx.Request.URL.Query()
}

// 根据参数名称，获取url参数的值
// @Param p  string  true 要获取的url参数名称
// @Return string url参数值
func (c *InterfaceusageController) GetURLParam(p string) string {
	v := c.GetURLQuery()
	return v.Get(p)
}

// @Description 返回文件、参数
// @Return File,FileHeader,map[string]string,error
func (c *InterfaceusageController) getParams() (h multipart.File, file *multipart.FileHeader, dataParams map[string]interface{}, err error) {
	var (
		api_id       string
		cached       string
		cachtime     int
		params       map[string]interface{}
		headers      map[string]interface{}
		interface_id int64
		id           string
		paramstr     string
		headerstr    string
	)
	h, file, err = c.GetFile("file")
	if err == nil && file != nil {
		cached = c.Ctx.Request.Form.Get("cached")
		cachtime, _ = strconv.Atoi(c.Ctx.Request.Form.Get("cachtime"))
		api_id = c.Ctx.Request.Form.Get("api_id")
		paramstr = c.Ctx.Request.Form.Get("params")
		id = c.Ctx.Request.Form.Get("interfaceId")
		headerstr = c.Ctx.Request.Form.Get("headers")
	} else {
		api_id = c.GetString("api_id")
		cached = c.GetString("cached")
		cachtime, _ = strconv.Atoi(c.GetString("cachtime"))
		paramstr = c.GetString("params")
		id = c.GetString("interfaceId")
		headerstr = c.GetString("headers")
	}
	if id == "" {
		err = errors.New("please choose the interface ID")
		return h, file, nil, err
	}
	if strings.Trim(headerstr, " ") == "" {
		headers = map[string]interface{}{}
	} else {
		err = ffjson.Unmarshal([]byte(headerstr), &headers)
		if err != nil {
			return h, file, nil, err
		}
	}
	interface_id, _ = strconv.ParseInt(id, 10, 64)
	interfacedefine, err := models.GetInterfacedefineById(interface_id)
	if err != nil {
		return h, file, nil, err
	}
	apiurl := interfacedefine.Url
	method := interfacedefine.Method
	staticParams := interfacedefine.StaticParams
	evalstr := strings.Trim(interfacedefine.EvalSrc, " ")
	evalUsefor := interfacedefine.EvalUsefor
	if evalstr != "" {
		interfaceusage, err := models.GetInterfaceusageByApiId(api_id)
		if err != nil {
			return h, file, nil, err
		}
		evalRes, err := GetEvalParams("", interfaceusage.ParamsExample, staticParams, evalstr)
		if err != nil {
			return h, file, nil, err
		}
		if evalUsefor == "headers" {
			for k, v := range evalRes {
				headers[k] = v
			}
			var pObj map[string]interface{}
			err = ffjson.Unmarshal([]byte(paramstr), &pObj)
			if err != nil {
				return h, file, nil, err
			}
			paramProp, ok := pObj["params"]
			if !ok {
				paramProp = pObj
			}
			// 如能转为map对象，则用转换后的，否则直接用全部的参数
			if pParams, ok := paramProp.(map[string]interface{}); ok {
				params = pParams["0"].(map[string]interface{})
			} else {
				params = paramProp.(map[string]interface{})
			}
		} else if evalUsefor == "params" {
			params = evalRes
		}
	} else {
		err = ffjson.Unmarshal([]byte(paramstr), &params)
		if err != nil {
			return h, file, nil, err
		}
	}

	dataParams = map[string]interface{}{
		"apiurl":       apiurl,
		"headers":      headers,
		"method":       method,
		"params":       params,
		"staticparams": staticParams,
		"api_id":       api_id,
		"cached":       cached,
		"cachtime":     cachtime,
	}
	return
}

// @Description
// @Return File,FileHeader,map[string]string,error
func (c *InterfaceusageController) GetData(h multipart.File, file *multipart.FileHeader, dataParams map[string]interface{}, hashkey string, mtime int) (returnData interface{}, err error) {
	var data []byte
	if file != nil {
		data, err = getUrlFilePost(h, ToString(dataParams["apiurl"]), file.Filename)
	} else {
		data, err = GetInterfaceData(dataParams)
	}
	if err != nil {
		return nil, err
	}
	if data != nil {
		if hashkey != "" && mtime > 0 {
			err = PutMemcache(hashkey, data, mtime)
		}
		m, err := DealData(data)
		if err != nil {
			return nil, err
		}
		returnData = m
	}
	return
}

// @Description 测试第三方接口，并返回结果,包括json和file方式
// @Return SunnyMsgStruct  json true
func (c *InterfaceusageController) TryInterface() {
	var msg string
	var (
		returnData interface{}
		err        error
	)
	sms := DmsResStruct{Msg: "", Data: nil, Status: false}
	h, file, dataParams, err := c.getParams()
	if err != nil {
		msg = err.Error()
		beego.Error(msg)
		return
	}

	if dataParams["cached"] == "1" {
		hashkey, err := GetHashKey(ToString(dataParams["api_id"]), ToString(dataParams["params"]))
		if err != nil {
			msg = err.Error()

			sms.Msg = msg
			c.ResReturn(sms)
			return
		}
		cachtime := dataParams["cachtime"].(int)
		result, istrue := GetMemcache(hashkey)
		if !istrue {
			returnData, err = c.GetData(h, file, dataParams, hashkey, cachtime)
			if err != nil {
				msg = err.Error()
				beego.Error(msg)
				sms.Msg = msg
				c.ResReturn(sms)
				return
			}
		} else {
			returnData, err = DealData(result)
			if err != nil {
				msg = err.Error()
				beego.Error(msg)
				sms.Msg = msg
				c.ResReturn(sms)
				return
			}
		}

	} else {
		returnData, err = c.GetData(h, file, dataParams, "", 0)
		if err != nil {
			msg = err.Error()
			beego.Error(msg)
			sms.Msg = msg
			c.ResReturn(sms)
			return
		}
	}

	if err != nil {
		msg = err.Error()
		sms.Msg = msg

	} else {
		sms.Data = returnData
	}
	c.ResReturn(sms)
}

//按定义模板输出内容
func (c *InterfaceusageController) GenerateData() {
	apiresult := c.GetString("apiresult")
	transall := c.GetString("transall")
	paramfor := c.GetString("paramfor")
	firstresult := c.GetString("firstresult")
	sms := DmsResStruct{Status: false, Msg: "", Data: ""}
	if apiresult == "" {
		sms.Msg = "API Data is empty"
		c.ResReturn(sms)
		return
	}
	if transall == "1" {
		sms.Data = apiresult
	} else {
		outstruct := c.GetString("outstruct")
		if outstruct == "" {
			sms.Msg = "OutPut struct is empty"
			c.ResReturn(sms)
			return
		}
		var m interface{}
		err := ffjson.Unmarshal([]byte(apiresult), &m)
		if err != nil {
			sms.Msg = err.Error()
			c.ResReturn(sms)
			return
		}
		templateStr, err := TemplateDeal(outstruct, m)
		if err != nil {
			sms.Msg = err.Error()
			c.ResReturn(sms)
			return
		}
		if paramfor == "outresult" && strings.Trim(firstresult, " ") != "" {
			mergedres, err := MergeResults(firstresult, templateStr)
			if err != nil {
				sms.Msg = err.Error()
				c.ResReturn(sms)
				return
			}
			sms.Data = mergedres
		} else {
			sms.Data = templateStr
		}
	}
	c.ResReturn(sms)
}

// Post ...
// @Title Post
// @Description create Interfacedefine
// @Param	body		body 	models.Interfacedefine	true		"body for Interfacedefine content"
// @Success 201 {int} models.Interfacedefine
// @Failure 403 body is empty
// @router / [post]
func (c *InterfaceusageController) GetParams() {
	inter_id := c.GetString("interface_id")
	sms := DmsResStruct{Status: false, Msg : "", Data: ""}
	if inter_id == "" {
		sms.Msg = "no interface_id"
		c.ResReturn(sms)
	}
	interfaceUsage, err := models.GetInterfaceusageByApiId(inter_id)
	if err != nil {
		sms.Msg = err.Error()
		c.ResReturn(sms)
	}
	p := interfaceUsage.ParamsExample
	h := interfaceUsage.Headers
	paramtype := interfaceUsage.Paramtype
	outstruct := interfaceUsage.OutStruct
	data := map[string]string{"params": p, "headers": h, "paramtype": paramtype, "outstruct": outstruct}
	sms.Data = data
	c.ResReturn(sms)
}

// Post ...
// @Title Post
// @Description create Interfaceusage
// @Param	body		body 	models.Interfaceusage	true		"body for Interfaceusage content"
// @Success 201 {int} models.Interfaceusage
// @Failure 403 body is empty
// @router / [post]
func (c *InterfaceusageController) Post() {
	var v models.Interfaceusage
	if err := c.ParseForm(&v); err != nil {
		//c.Info(err)
		c.ShowMsg("添加失败", "/interfaceusage/list", 3)
	} else {
		if _, err := models.AddInterfaceusage(&v); err == nil {
			//c.Info(&v)
			c.ShowMsg("添加成功", "/interfaceusage/list", 3)
		} else {
			//c.Info(err)
			c.ShowMsg("添加失败", "/interfaceusage/list", 3)
		}
	}
}

// Update ...
// @Title Update
// @Description update the Skill
// @Param	id		path 	string	true		"The id you want to update"
// @Param	body		body 	models.Skill	true		"body for Skill content"
// @Success 200 {object} models.Skill
// @Failure 403 :id is not int
// @router /:id [Update]
func (c *InterfaceusageController) Update() {
	var v models.Interfaceusage
	if err := c.ParseForm(&v); err != nil {
		//c.Info(err)
		c.ShowMsg("保存失败", "/interfaceusage/list", 3)
	} else {
		if err := models.UpdateInterfaceusageById(&v); err == nil {
			c.ShowMsg("保存成功", "/interfaceusage/list", 3)
		} else {
			c.ShowMsg("保存失败", "/interfaceusage/list", 3)
		}
	}
}

//编辑
func (c *InterfaceusageController) Edit() {
	if c.IsSubmit() {
		var e models.Interfaceusage
		if err := c.ParseForm(&e); err != nil {
			c.ShowMsg("接收表单失败，请重试!",   "-1", 4)
		} else {

			e.Pubtime = time.Now().Format("2006-01-02 15:04:05")
			cols := []string{"name", "api_id", "description", "params_map", "params_example", "outstruct", "cached", "trans_all", "interface_after_apiid", "interface_after_usage", "headers", "cachtime"}
			err := models.UpdateInterfaceusageById(&e, cols...)
			if err != nil {
				c.ShowMsg("修改失败了",   "/interfaceusage/list", 3)
			} else {
				models.ClearInterfaceusageCacheByApiId(e.ApiId)
				c.ShowMsg("修改成功了",  "/interfaceusage/list", 3)
			}
		}
	} else {
		_, actionName := c.GetControllerAndAction()
		c.Data["ACTION_NAME"] = actionName

		var id int64
		mapp := c.Ctx.Input.Params()
		id, _ = strconv.ParseInt(mapp["1"], 10, 64)
		data, _ := models.GetInterfaceusageById(id)
		interfaceDefine, _ := models.GetInterfacedefineById(data.InterfaceId)
		interfaceAfter, _ := models.GetInterfaceusageByApiId(data.InterfaceAfterApiID)
		interfaceafterList, _ := models.GetInterfaceUsageList()
		c.Data["interfaceafterList"] = interfaceafterList
		c.Data["interfaceafter"] = interfaceAfter
		c.Data["corr_interfacedefine"] = interfaceDefine
		c.Data["Data"] = data
		c.TplName = "interfaceusage/form.html"
	}
}

//添加
func (c *InterfaceusageController) Add() {
	if c.IsSubmit() {
		var e models.Interfaceusage

		if err := c.ParseForm(&e); err != nil {
			c.ShowMsg("接收表单失败，请重试!",   "-1", 4)
		} else {

			e.Pubtime = time.Now().Format("2006-01-02 15:04:05")
			_, err := models.AddInterfaceusage(&e)
			beego.Error(err)
			if err != nil {
				c.ShowMsg("添加失败了",  "/interfaceusage/list", 3)
			} else {
				models.ClearInterfaceusageCacheByApiId(e.ApiId)
				c.ShowMsg("添加成功了",   "/interfaceusage/list", 3)
			}
		}
	} else {
		_, actionName := c.GetControllerAndAction()
		c.Data["ACTION_NAME"] = actionName
		interfaceDefine, _ := models.GetInterfaceDefineList()
		c.Data["interfacedefine"] = interfaceDefine
		interfaceUsage, _ := models.GetInterfaceUsageList()
		c.Data["interfaceafterList"] = interfaceUsage
		c.Data["Data"] = map[string]interface{}{"InterfaceAfterApiID": ""}
		c.TplName = "interfaceusage/form.html"
	}
}

// GetOne ...
// @Title Get One
// @Description get Interfaceusage by id
// @Param	id		path 	string	true		"The key for staticblock"
// @Success 200 {object} models.Interfaceusage
// @Failure 403 :id is empty
// @router /:id [get]
func (c *InterfaceusageController) GetOne() {
	idStr := c.Ctx.Input.Param(":id")
	id, _ := strconv.ParseInt(idStr, 10, 64)
	v, err := models.GetInterfaceusageById(id)
	if err != nil {
		c.Data["json"] = err.Error()
	} else {
		c.Data["json"] = v
	}
	c.ServeJSON()
}

// GetAll ...
// @Title Get All
// @Description get Interfaceusage
// @Param	query	query	string	false	"Filter. e.g. col1:v1,col2:v2 ..."
// @Param	fields	query	string	false	"Fields returned. e.g. col1,col2 ..."
// @Param	sortby	query	string	false	"Sorted-by fields. e.g. col1,col2 ..."
// @Param	order	query	string	false	"Order corresponding to each sortby field, if single value, apply to all sortby fields. e.g. desc,asc ..."
// @Param	limit	query	string	false	"Limit the size of result set. Must be an integer"
// @Param	offset	query	string	false	"Start position of result set. Must be an integer"
// @Success 200 {object} models.Interfaceusage
// @Failure 403
// @router / [get]
func (c *InterfaceusageController) List() {
	var fields []string
	var sortby []string
	var order []string
	var query = make(map[string]string)
	var limit int64 = 30
	var offset int64
	var page int64
	if v, err := c.GetInt64("p"); err == nil {
		page = v
		offset = (page - 1) * limit
	} else {
		page = 1
		offset = 0
	}
	// fields: col1,col2,entity.col3
	if v := c.GetString("fields"); v != "" {
		fields = strings.Split(v, ",")
	}
	// limit: 10 (default is 10)
	if v, err := c.GetInt64("limit"); err == nil {
		limit = v
	}
	// offset: 0 (default is 0)
	if v, err := c.GetInt64("offset"); err == nil {
		offset = v
	}
	// sortby: col1,col2
	if v := c.GetString("sortby"); v != "" {
		sortby = strings.Split(v, ",")
	}
	// order: desc,asc
	if v := c.GetString("order"); v != "" {
		order = strings.Split(v, ",")
	}
	// query: k:v,k:v
	if v := c.GetString("query"); v != "" {
		for _, cond := range strings.Split(v, ",") {
			kv := strings.SplitN(cond, ":", 2)
			if len(kv) != 2 {
				c.Data["json"] = errors.New("Error: invalid query key/value pair")
				c.ServeJSON()
				return
			}
			k, v := kv[0], kv[1]
			query[k] = v
		}
	}
	name := c.GetString("name")
	q := make([]string, 0)
	if name != "" {
		q = append(q, `Name:`+name)
	}
	for _, cond := range q {
		kv := strings.SplitN(cond, ":", 2)
		if len(kv) != 2 {
			c.Data["json"] = errors.New("Error: invalid query key/value pair")
			c.ServeJSON()
			return
		}
		k, v := kv[0], kv[1]
		query[k] = v
	}
	sortby = append(sortby, "id")
	order = append(order, "desc")
	sortby = append(sortby, "name")
	order = append(order, "desc")
	l, count, err := models.GetAllInterfaceusage(query, fields, sortby, order, offset, limit)
	if err != nil {
		c.Data["list"] = nil
	} else {
		c.Data["list"] = l
		if count > 1 {
			c.Data["Page"] = PageUtil(int(count), int(page), int(limit), l)
		}
	}
	c.TplName = "interfaceusage/list.html"
}

// Put ...
// @Title Put
// @Description update the Interfaceusage
// @Param	id		path 	string	true		"The id you want to update"
// @Param	body		body 	models.Interfaceusage	true		"body for Interfaceusage content"
// @Success 200 {object} models.Interfaceusage
// @Failure 403 :id is not int
// @router /:id [put]
func (c *InterfaceusageController) Put() {
	idStr := c.Ctx.Input.Param(":id")
	id, _ := strconv.ParseInt(idStr, 10, 64)
	v := models.Interfaceusage{Id: id}
	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &v); err == nil {
		if err := models.UpdateInterfaceusageById(&v); err == nil {
			c.Data["json"] = "OK"
		} else {
			c.Data["json"] = err.Error()
		}
	} else {
		c.Data["json"] = err.Error()
	}
	c.ServeJSON()
}

// Delete ...
// @Title Delete
// @Description delete the Interfaceusage
// @Param	id		path 	string	true		"The id you want to delete"
// @Success 200 {string} delete success!
// @Failure 403 id is empty
// @router /:id [delete]
func (c *InterfaceusageController) Delete() {
	mapp := c.Ctx.Input.Params()
	id, _ := strconv.ParseInt(mapp["1"], 10, 64)
	usage, _ := models.GetInterfaceusageById(id)
	if err := models.DeleteInterfaceusage(id); err == nil {
		models.ClearInterfaceusageCacheByApiId(usage.ApiId)
		c.ShowMsg("删除成功了",  "/interfaceusage/list.html", 3)
	} else {
		c.ShowMsg("删除失败",  "/interfaceusage/list.html", 3)
	}
}
